#include "udpServer.hpp"
#include "onlineUser.hpp"

#include <memory>
#include <signal.h>
#include <fstream>
using namespace Server;

const string dictTxt = "./dict.txt";
unordered_map<string,string> dict;
// 提示 运行格式
static void Usage(string proc)
{
    cout<<"Usage:\n\t" << proc <<" local_port\n\n";
}
//切割dict.txt文本内容
static bool cutString(string& target,string* s1,string* s2,const string sep)
{
    auto pos = target.find(sep);
    if(pos == string::npos)
        return false;

    *s1 = target.substr(0,pos); //[)
    *s2 = target.substr(pos+sep.size()); //[)
    return true;
}
//输出字典内容
static void debugPrint()
{
    for(const auto& dt : dict)
    {
        cout << dt.first << " # " << dt.second << endl;
    }
}
//初始化字典
static void initDict()
{
    ifstream in(dictTxt,std::ios::binary);
    if(!in.is_open())
    {
        cerr << "open file " << dictTxt << " error" << endl;
        exit(OPEN_ERR);
    }
    string line;
    string key,value;
    while(getline(in,line))
    {
        // cout << line << endl;
        if(cutString(line,&key,&value,":"))
        {
            dict.insert(make_pair(key,value));
        }
    }
    in.close();
    cout << "load dict success " << endl;
}
//对捕捉的信号做自定义动作，该函数是 不退出就可以更新字典内容
void reload(int signo)
{
    (void)signo;
    initDict(); //初始化字典
}
//1. 一个翻译业务
void handlerMessage(int sockfd,string Clientip,uint16_t Clientport,string message)
{
    //就可以对message进行特定的业务处理，而不关心message怎么来的 -----  Server 通信和业务逻辑解耦
    //婴儿版的业务逻辑
    string response_message;
    auto iter = dict.find(message);
    if(iter == dict.end())
        response_message = "unkown";    //字典里找不到输入内容，就输出不知道
    else
        response_message = iter->second;
    
    //开始返回
    struct sockaddr_in client;
    bzero(&client,sizeof(client));

    client.sin_family = AF_INET;
    client.sin_port = htons(Clientport);
    client.sin_addr.s_addr = inet_addr(Clientip.c_str());

    sendto(sockfd,response_message.c_str(),response_message.size(),0,(struct sockaddr*)&client,sizeof(client));
    
    // cout << "服务器翻译结果# " << response_message << endl;
}

//2. 一个命令行业务
void execCommand(int sockfd,string Clientip,uint16_t Clientport,string cmd)
{   
    //禁止操作的命令
    if(cmd.find("rm") != string::npos || 
    cmd.find("mv") != string::npos || 
    cmd.find("rmdir") != string::npos)
    {
        cerr << Clientip << " : " << Clientport << " 正在做一个非法的操作：" << cmd << endl;
        return;
    }

    string response;
    FILE* fp = popen(cmd.c_str(),"r");  //popen = pipe + fork + exec
    if(fp == nullptr) response = cmd + "exec failed";
    char line[1024];
    while(fgets(line,sizeof(line),fp))
    {
        response += line;
    }
    pclose(fp);

    //开始返回
    struct sockaddr_in client;
    bzero(&client,sizeof(client));

    client.sin_family = AF_INET;
    client.sin_port = htons(Clientport);
    client.sin_addr.s_addr = inet_addr(Clientip.c_str());

    sendto(sockfd,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof(client));
}
//3. 多人对话服务
OnlineUser oluser;  //对象

void routemessage(int sockfd,string Clientip,uint16_t Clientport,string message)
{
    if(message == "online")
        oluser.addUser(Clientip,Clientport);
    if(message == "offline")
        oluser.delUser(Clientip,Clientport);
    if(oluser.isOnline(Clientip,Clientport))
    {
        //消息的路由
        oluser.broadcastMessage(sockfd,Clientip,Clientport,message);
    }
    else
    {
        struct sockaddr_in client;
        bzero(&client,sizeof(client));

        client.sin_family = AF_INET;
        client.sin_port = htons(Clientport);
        client.sin_addr.s_addr = inet_addr(Clientip.c_str());

        string response = "你还没有上线，请先上线！上线请运行：online \n";
        sendto(sockfd,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof(client));
    }
}
//  ./udpServer port
int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    // string ip = argv[1];

    //1.
    // signal(2,reload);//对2号信号做捕捉
    // initDict(); //初始化字典
    // debugPrint();
    // unique_ptr<udpServer> usvr(new udpServer(handlerMessage,port)); //1.

    // unique_ptr<udpServer> usvr(new udpServer(execCommand,port));     //2.

    unique_ptr<udpServer> usvr(new udpServer(routemessage,port));    //3.

    usvr->initServer(); //初始化服务器
    usvr->start();      //运行服务器

    return 0;
}